package com.javaobj.auth.security.jwt;

import com.google.common.base.Strings;
import com.javaobj.auth.config.AuthConfigurationProperties;
import com.javaobj.auth.security.authentication.ResponseResultAuthenticationAccessDeniedHandler;
import com.javaobj.auth.security.authentication.ResponseResultAuthenticationEndpoint;
import com.nimbusds.jose.util.StandardCharset;
import org.springframework.context.ApplicationContext;
import org.springframework.core.convert.converter.Converter;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.authentication.AuthenticationManagerResolver;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.annotation.web.configurers.oauth2.server.resource.OAuth2ResourceServerConfigurer;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;
import org.springframework.security.oauth2.server.resource.web.BearerTokenResolver;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.AccessDeniedHandler;

import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.HttpServletRequest;


public class JwtSecurityConfigurer extends AbstractHttpConfigurer<JwtSecurityConfigurer, HttpSecurity> {


    /**
     * 默认无权限处理类
     * @return
     */
    private AccessDeniedHandler accessDeniedHandler = new ResponseResultAuthenticationAccessDeniedHandler();



    /**
     * 默认认证类
     * @return
     */
    private AuthenticationEntryPoint authenticationEntryPoint = new ResponseResultAuthenticationEndpoint();


    /**
     * 解析请求中的JWT
     * @return
     */
    private BearerTokenResolver bearerTokenResolver = new NullableBearerTokenResolver();


    /**
     * JWT 认证管理器
     * @param jwtDecoder
     * @return
     */
    private  AuthenticationManagerResolver<HttpServletRequest> authenticationManagerResolver;


    /**
     * JWT 信息转换接口
     */
    private Converter<Jwt, ? extends AbstractAuthenticationToken> jwtAuthenticationConverter = new JwtAuthenticationConverter();



    /**
     * Token 解析器
     */
    private JwtDecoder jwtDecoder;



    @Override
    public void init(HttpSecurity builder) throws Exception {
        super.init(builder);



        ApplicationContext context = builder.getSharedObject(ApplicationContext.class);
        AuthConfigurationProperties properties = context.getBean(AuthConfigurationProperties.class);
        AuthConfigurationProperties.Jwt jwt = properties.getJwt();



        //没有配置jwt不配置oauth2
        if (Strings.isNullOrEmpty(jwt.getKeyValue())) {
            return;
        }

        final SecretKey JWT_KEY = new SecretKeySpec(jwt.getKeyValue().getBytes(StandardCharset.UTF_8), jwt.getAlgorithm());
        jwtDecoder =     NimbusJwtDecoder.withSecretKey(JWT_KEY).build();



        //Apply oauth OAuth2ResourceServerConfigurer
//        builder.oauth2ResourceServer();
    }

    @Override
    public void configure(HttpSecurity builder) throws Exception {
        super.configure(builder);


        OAuth2ResourceServerConfigurer configurer = builder.getConfigurer(OAuth2ResourceServerConfigurer.class);
        if(configurer == null || jwtDecoder == null){
            return;
        }

        configurer = builder.oauth2ResourceServer();

        configurer.authenticationEntryPoint(authenticationEntryPoint);
        configurer.accessDeniedHandler(accessDeniedHandler);
        configurer.bearerTokenResolver(bearerTokenResolver);

        if (authenticationManagerResolver == null) {

            //使用默认的 AuthenticationManager
            JWTAuthenticationManager authenticationManager = new JWTAuthenticationManager(jwtDecoder);
            authenticationManager.setJwtAuthenticationConverter(jwtAuthenticationConverter);
            configurer.authenticationManagerResolver((ctx -> authenticationManager));
        }else{
            configurer.authenticationManagerResolver(authenticationManagerResolver);
        }
    }





    /***
     * 设置 JWT 转换器
     * @param jwtAuthenticationConverter
     */
    public JwtSecurityConfigurer jwtAuthenticationConverter(Converter<Jwt, ? extends AbstractAuthenticationToken> jwtAuthenticationConverter) {
        this.jwtAuthenticationConverter = jwtAuthenticationConverter;
        return this;
    }

    /**
     * 设置授权入口点
     * @param authenticationEntryPoint
     * @return
     */
    public JwtSecurityConfigurer authenticationEntryPoint(AuthenticationEntryPoint authenticationEntryPoint) {
        this.authenticationEntryPoint = authenticationEntryPoint;
        return this;
    }
}
